#ifndef KERNEL_P_H
#define KERNEL_P_H

#include <QtCore/QObject>
#include <QtCore/QSettings>
#include <QtCore/QFile>
#include <QtCore/QRegExp>
#include <QtNetwork/QTcpSocket>
#include "kernel/source_server.h"

namespace smstranslator {

class Kernel;
#ifdef WITH_ZABBIX
class ZabbixWriter;
#endif

class KernelPrivate : public QObject {
  Q_OBJECT
public:
  KernelPrivate(Kernel *parent, log::LogManager *log_manager);

  ~KernelPrivate();

  void start();

protected:

  void timerEvent(QTimerEvent *);

private slots:

  void reloadConfig(QSettings *config);

  void newSrc(int socket_descriptor);

  void stop();

  void openedDest();

  void closedDest();

  void receiveDest(const smpp::pdu::BindTransmitterResp &p);

  void receiveDest(const smpp::pdu::BindReceiverResp &p);

  void receiveDest(const smpp::pdu::BindTransceiverResp &p);

  void receiveDest(const smpp::pdu::UnbindResp &p);

  void sessionInitDest();

  void errorDest(smpp::sessions::ErrorCode code);

  void openedSrc();

  void closedSrc();

  void receiveSrc(const smpp::pdu::BindTransmitter &p);

  void receiveSrc(const smpp::pdu::BindReceiver &p);

  void receiveSrc(const smpp::pdu::BindTransceiver &p);

  void receiveSrc(const smpp::pdu::EnquireLink &p);

  void receiveSrc(const smpp::pdu::SubmitSm &p);

  void receiveSrc(const smpp::pdu::QuerySm &p);

  void receiveSrc(const smpp::pdu::ReplaceSm &p);

  void receiveSrc(const smpp::pdu::CancelSm &p);

  void receiveDest(const smpp::pdu::DeliverSm &p);

  void inStatusSrc(const smpp::pdu::Header &header,
                   smpp::sessions::StatusMessage status);

  void sessionInitSrc();

  void errorSrc(smpp::sessions::ErrorCode code);

signals:
#ifdef WITH_ZABBIX
  void writeZabbix(const QByteArray &msg);
#endif
  void sigStop();

  void sigReloadConfig(QSettings *config);

private:

  void incrementSessionCounter(const QString &system_id);

  bool readConfig(QSettings *config);

  void setState(State state);

  void checkState();

  QString stateToString(smpp::sessions::SessionStates state) const;

  void startStatTimer();

  void stopStatTimer();
#ifdef WITH_ZABBIX
  void startZabbixTimer();

  void stopZabbixTimer();
#endif
  void writeStat();
#ifdef WITH_ZABBIX
  void writeZabbix();
#endif
  void clearPacketsOnClose(smpp::sessions::ServerAsyncSession *src_session);

  friend class Kernel;
#ifdef WITH_ZABBIX
  friend class ZabbixWriter;
#endif

  Kernel *parent;

  class Client {
  public:
    Client(QRegExp access_ip,
           QRegExp access_sid,
           int max_in_speed,
           int max_out_speed,
           int max_in_trans,
           int max_out_trans) :
      access_ip(access_ip),
      access_sid(access_sid),
      max_in_speed(max_in_speed),
      max_out_speed(max_out_speed),
      max_in_trans(max_in_trans),
      max_out_trans(max_out_trans) {

    }

    ~Client() {}

    QRegExp access_ip;
    QRegExp access_sid;
    int max_in_speed;
    int max_out_speed;
    int max_in_trans;
    int max_out_trans;
  };

  class TranslateReglation {
  public:
    TranslateReglation(const QRegExp &dest_addr,
                       quint8 before_ton,
                       quint8 before_npi,
                       const QString &before_addr,
                       quint8 after_ton,
                       quint8 after_npi,
                       const QString &after_addr) :
      dest_addr(dest_addr),
      before_ton(before_ton),
      before_npi(before_npi),
      before_addr(before_addr),
      after_ton(after_ton),
      after_npi(after_npi),
      after_addr(after_addr) {

    }

    ~TranslateReglation() {}

    QRegExp dest_addr;
    quint8 before_ton;
    quint8 before_npi;
    QString before_addr;
    quint8 after_ton;
    quint8 after_npi;
    QString after_addr;
  };

#ifdef WITH_ZABBIX
  class ZabbixStat {
  public:
    ZabbixStat(int in_speed, int out_speed) :
      in_speed(in_speed), out_speed(out_speed) {

    }

    ~ZabbixStat() {

    }

    int in_speed;
    int out_speed;
  };
#endif

  log::LogLevel log_level;

  SourceServer *server;
  QHostAddress server_addr;
  quint16 server_port;

  QHostAddress smsc_addr;
  quint16 smsc_port;

  QList<Client *> clients;

  QHash<smpp::sessions::ServerAsyncSession *,
        QList<smpp::pdu::Header *> > packets_on_close;

  QHash<smpp::sessions::ServerAsyncSession *,
        smpp::sessions::ClientAsyncSession *> linked_sessions;

  QHash<smpp::sessions::ServerAsyncSession *, QString> sid_sessions;

  QHash<smpp::sessions::ServerAsyncSession *, Client *> client_sessions;

  QHash<smpp::sessions::ServerAsyncSession *, QString> sid_client_sessions;

  State state;

  log::LogManager *log_manager;

  QFile *stat_file;

  QString last_error;

  int stat_time;
  int stat_timer;

#ifdef WITH_ZABBIX
  int zabbix_time;
  int zabbix_timer;

  QHostAddress zabbix_addr;
  quint16 zabbix_port;

  ZabbixWriter *zabbix;
#endif

  QList<TranslateReglation *> table_translate;

  QtJsonSettings *counter_file;
};

} // namespace smstranslator

#endif // KERNEL_P_H
